using System.Collections.Generic;
using Microsoft.Xna.Framework;
using PoolGame2.Assets;
using PoolGame2.Controls;
using PoolGame2.Physics;

namespace PoolGame2.Game
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    /// 
    
    public class Cue: GameObject, IGameControlListener
    {
        private GameObject cueBall;
        
        private float shotPower = 0.0f;
        private Vector3 cueTipPosition = Vector3.Zero;
        private bool shotStarted = false;

        public Cue (PoolGame game, ModelObject modelO, PhysicsObject physicsO, GameObject cBall)
            : base(game, modelO, physicsO, "cue")
        {
            cueBall = cBall;
            base.rotation.Y = 0;
            base.position = cueBall.getPosition();
            base.position.X += 0.5f;
            base.rotation.Z = 0.15f;
       }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            if (shotStarted)
            {
                shotPower += GameConstants.SHOT_POWER_INCREMENT;
                if (shotPower > GameConstants.MAX_SHOT_POWER)
                {
                    shotPower = GameConstants.MAX_SHOT_POWER;
                }
               
            }
            cueTipPosition = PoolGame.gameControls.MoveCueTip(cueTipPosition);
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            if (((PoolGame)base.Game).gameManager.GetState() == Managers.ManagerGame.GameState.GAME_PLAYER_TAKING_SHOT)
            {
                base.position = cueBall.getPosition() + cueTipPosition;
                base.Draw(gameTime);
            }
        }

        public void ResetPowerAndCueTipPosition() {
            this.shotPower = 0.0f;
            this.cueTipPosition = Vector3.Zero;
            this.shotStarted = false;
        }

        public void SetShotPower(float shotPower)
        {
            this.shotPower = shotPower;
        }

        public float GetShotPower(){ return shotPower; }

        public Vector3 GetCueTipPosition() { return cueTipPosition; }

        
        public void GameControlPerformed(List<GameControlAction> actions)
        {
            foreach (GameControlAction action in actions)
            {
               ControlActions a = action.GetAction();
                if (a == ControlActions.START_SHOT)
                {
                    this.shotStarted = true;
                }
                else if (a == ControlActions.END_SHOT)
                {
                    this.shotStarted = false;
                }
                else if (a == ControlActions.CUE_MOVEMENT)
                {
                    float x = (float)action.GetProperty(GameConstants.X_CHANGE) * GameConstants.CUE_MOVEMENT_SCALE;
                    float y = (float)action.GetProperty(GameConstants.Y_CHANGE) * GameConstants.CUE_MOVEMENT_SCALE;
                    base.rotation.Y += x;
                    // TODO: Rotate about the arbitrary angle
                    
                }
                else if (a == ControlActions.CUE_TIP_MOVEMENT)
                {
                    Vector3 orientedXAxis = this.GetUnitVectorDirection();
                    orientedXAxis = Vector3.Negate(orientedXAxis);
                    orientedXAxis = Vector3.Cross(orientedXAxis, Vector3.Up);
                    orientedXAxis.Normalize();

                    float x = (float)action.GetProperty(GameConstants.X_CHANGE) * GameConstants.CUE_TIP_MOVEMENT_SCALE;
                    cueTipPosition += orientedXAxis * x;
                    
                    float y = (float)action.GetProperty(GameConstants.Y_CHANGE) * GameConstants.CUE_TIP_MOVEMENT_SCALE;
                    cueTipPosition.Y -= y;
                    ClampCueTipPosition();
                }
            }
        }

        private void ClampCueTipPosition()
        {
            // TO DO - CLAMP BASED of the dimensions of a sphere
            cueTipPosition.X = MathHelper.Clamp(cueTipPosition.X, -(PhysicsConstants.DEFAULT_RADIUS * 0.7f), (PhysicsConstants.DEFAULT_RADIUS * 0.7f));
            cueTipPosition.Y = MathHelper.Clamp(cueTipPosition.Y, -(PhysicsConstants.DEFAULT_RADIUS * 0.7f), (PhysicsConstants.DEFAULT_RADIUS * 0.7f));
            cueTipPosition.Z = MathHelper.Clamp(cueTipPosition.Z, -(PhysicsConstants.DEFAULT_RADIUS * 0.7f), (PhysicsConstants.DEFAULT_RADIUS * 0.7f));
        }

        public Vector3 GetUnitVectorDirection()
        {
            Vector3 strikeDirection = Vector3.UnitX;
            Matrix mat = Matrix.CreateRotationY(this.getRotation().Y);
            strikeDirection = Vector3.Transform(strikeDirection, mat);
            strikeDirection.Normalize();
            return strikeDirection;
        }

    }
}